﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CommonHelper.TcpHelper
{
    #region 枚举定义
    /// <summary>
    /// 消息类型
    /// </summary>
    public enum MessageType
    {
        Normal,
        warning,
        Error,
    }

    #endregion

    #region 事件参数
    public class ServerReceiveDataEventArgs : EventArgs
    {
        public ConnectedClient Client;
        public byte[] ReceiveData;
        public DateTime Time { get; set; }

        public ServerReceiveDataEventArgs(ConnectedClient Client, byte[] ReceiveData)
        {
            this.ReceiveData = ReceiveData;
            this.Client = Client;
            Time = DateTime.Now;
        }
    }
    public class ClientLineStateChangedEventArgs : EventArgs
    {
        public ConnectedClient Client { get; set; }
        public LineState State { get; set; }
        public DateTime Time { get; set; }
        public ClientLineStateChangedEventArgs(ConnectedClient Client, LineState State)
        {
            this.Client = Client;
            this.State = State;
            Time=DateTime.Now;
        }
    }

    /// <summary>
    /// 客户端在线状态
    /// </summary>
    public enum LineState
    {
        OnLine,
        OffLine,
    }

    public class TcpMessageEventArgs
    {
        /// <summary>
        /// 消息类型
        /// </summary>
        public MessageType EventType { get; set; }
        /// <summary>
        /// 消息内容
        /// </summary>
        public string Message { get; set; }

        /// <summary>
        /// 消息发生的时间
        /// </summary>
        public DateTime Time { get; set; }
        public TcpMessageEventArgs(MessageType EventType, string Message)
        {
            this.EventType = EventType;
            this.Message = Message;
            Time = DateTime.Now;
        }
    }
    #endregion

    #region 服务端
    public class TCP_Server
    {
        public event EventHandler<ServerReceiveDataEventArgs> ReceiveDataEvent;
        public event EventHandler<ClientLineStateChangedEventArgs> ClientLineStateChangedEvent;
        public event EventHandler<TcpMessageEventArgs> MessageEvent;

        /// <summary>
        /// 标识服务器是否已经停止！
        /// </summary>
        bool _IsStop = true;
        object obj = new object();
        /// <summary>
        /// 信号量
        /// </summary>
        Semaphore semap = new Semaphore(5, 5000);
        /// <summary>
        /// 客户端队列集合
        /// </summary>
        public List<ConnectedClient> ConnectedClients = new List<ConnectedClient>();
        /// <summary>
        /// 服务端监听连接的TcpListener
        /// </summary>
        TcpListener listener;
        public bool IsStop()
        {
            return _IsStop;
        }

        /// <summary>
        /// 初始化服务端对象
        /// </summary>
        /// <param name="ipaddress">IP地址</param>
        /// <param name="port">监听端口</param>
        public void Init(IPAddress iP, int port)
        {
            listener = new TcpListener(new IPEndPoint(iP, port));
        }
        /// <summary>
        /// 初始化服务端对象 监听Any即所有网卡
        /// </summary>
        /// <param name="ipaddress">IP地址</param>
        /// <param name="port">监听端口</param>
        public void Init(int port)
        {
            listener = new TcpListener(new IPEndPoint(IPAddress.Any, port));
        }
        /// <summary>
        /// 初始化服务端对象
        /// </summary>
        /// <param name="ipaddress">IP地址</param>
        /// <param name="port">监听端口</param>
        public void Init(string ipaddress, int port)
        {
            listener = new TcpListener(new IPEndPoint(IPAddress.Parse(ipaddress), port));
        }
        /// <summary>
        /// 启动监听,并处理连接
        /// </summary>
        public void Start()
        {
            try
            {
                if (_IsStop == true)
                {
                    listener.Start();
                    _IsStop = false;
                    Task.Run(new Action(() =>
                    {
                        while (true)
                        {
                            if (_IsStop == true)
                            {
                                break;
                            }
                            GetAcceptTcpClient();
                            Thread.Sleep(1);
                        }
                    }));
                }
            }
            catch (SocketException e)
            {
                listener.Stop();
                _IsStop = true;
                throw e;
            }
        }
        /// <summary>
        /// 等待处理新的连接
        /// </summary>
        void GetAcceptTcpClient()
        {
            try
            {
                semap.WaitOne();
                //获取连接的客户端；
                TcpClient tclient = listener.AcceptTcpClient();//此语句会死锁当前线程，直到有客户端连接；
                ConnectedClient client = new ConnectedClient() { Client = tclient };//保存连接的客户端；
                //加入客户端集合.
                AddClientList(client);//将连接的客户端添加到客户端列表；

                ClientLineStateChangedEventArgs e = new ClientLineStateChangedEventArgs(client,LineState.OnLine); //通知客户端上线；
                if (ClientLineStateChangedEvent != null)
                {
                    ClientLineStateChangedEvent.Invoke(this, e);
                }

                //上线的客户端异步接收数据；
                tclient.Client.BeginReceive(client.RecBuffer, 0, client.RecBuffer.Length, 0, new AsyncCallback(EndReader), client);// 
                semap.Release();
            }
            catch (Exception exs)
            {
                semap.Release();
                TcpMessageEventArgs e = new TcpMessageEventArgs(MessageType.Error, exs.ToString());
                if (MessageEvent != null)
                {
                    MessageEvent.Invoke(this, e);
                }
            }
        }

        /// <summary>
        /// 异步接收信息.数据接收完成后的回调函数；
        /// </summary>
        /// <param name="ir"></param>
        void EndReader(IAsyncResult ir)
        {
            ConnectedClient client = ir.AsyncState as ConnectedClient;
            if (client != null && listener != null)
            {
                try
                {
                    int ReceiveDataLengh = client.Client.GetStream().EndRead(ir);//endreader 停止异步接收并返回接收到的字节数；
                    if (ReceiveDataLengh != 0)//长度不为零，说明不是下线通知，而是正常的数据
                    {
                        byte[] DataTemp = new byte[ReceiveDataLengh];
                        Array.Copy(client.RecBuffer, DataTemp, ReceiveDataLengh);
                        ServerReceiveDataEventArgs e = new ServerReceiveDataEventArgs(client, DataTemp);
                        if (ReceiveDataEvent != null)
                        {
                            ReceiveDataEvent.Invoke(this, e);
                        }
                        //继续下一次的接收；
                        client.Client.Client.BeginReceive(client.RecBuffer, 0, client.RecBuffer.Length, 0, new AsyncCallback(EndReader), client);
                    }
                    else//客户端下线，接收的数据长度为零，为下线通知；
                    {
                        ConnectedClients.Remove(client);
                        ClientLineStateChangedEventArgs e = new ClientLineStateChangedEventArgs(client,LineState.OffLine);
                        if (ClientLineStateChangedEvent != null)
                        {
                            ClientLineStateChangedEvent.Invoke(this, e);
                        }
                    }
                }
                catch (Exception skex)
                {
                    lock (obj)
                    {
                        TcpMessageEventArgs e = new TcpMessageEventArgs(MessageType.Error, skex.ToString());
                        if (MessageEvent != null)
                        {
                            MessageEvent.Invoke(this, e);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 加入队列.
        /// </summary>
        /// <param name="sk"></param>
         void AddClientList(ConnectedClient sk)
        {
            //判断现有的客户端列表中是否已经包含要添加的对象；
            ConnectedClient sockets = ConnectedClients.Find(o => o.ToString() == sk.ToString());
            //如果不存在则添加,否则更新
            if (sockets == null)
            {
                ConnectedClients.Add(sk);
            }
            else
            {
                ConnectedClients.Remove(sockets);
                ConnectedClients.Add(sk);
            }
        }
        public void Stop()
        {
            if (listener != null)
            {
                SendToAll("");
                //关闭列表中的所有客户端连接；
                for (int i = 0; i < ConnectedClients.Count; i++)
                {
                    ConnectedClients[i].Client.Close();
                }
                ConnectedClients.Clear();
                listener.Stop();
                listener = null;
                _IsStop = true;
            }
        }
        /// <summary>
        /// 向所有在线的客户端发送信息.
        /// </summary>
        /// <param name="SendData">发送的文本</param>
        public void SendToAll(string SendData)
        {
            for (int i = 0; i < ConnectedClients.Count; i++)
            {
                SendToClient(ConnectedClients[i], SendData);
            }
        }
        /// <summary>
        /// 向所有在线的客户端发送信息.
        /// </summary>
        /// <param name="SendData">发送的数据</param>
        public void SendToAll(byte[] SendDataBuffer)
        {
            for (int i = 0; i < ConnectedClients.Count; i++)
            {
                SendToClient(ConnectedClients[i], SendDataBuffer);
            }
        }
        /// <summary>
        /// 向某一位客户端发送信息
        /// </summary>
        /// <param name="ip">客户端IP+端口地址</param>
        /// <param name="SendData">发送的数据包</param>
        public void SendToClient(ConnectedClient Client, byte[] SendDataBuffer)
        {
            try
            {
                //判断客户端列表中是否存在要发送消息的客户端；
                ConnectedClient sks = ConnectedClients.Find(o=>o.Equals(Client));
                if (sks != null)
                {
                    if (sks.Client.Connected)
                    {
                        sks.SendBuffer = SendDataBuffer;
                        sks.Client.Client.Send(sks.SendBuffer, sks.SendBuffer.Length, 0);
                    }
                }
            }
            catch (Exception skex)
            {
                TcpMessageEventArgs e = new TcpMessageEventArgs(MessageType.Error, skex.ToString());
                if (MessageEvent != null)
                {
                    MessageEvent.Invoke(this, e);
                }
            }
        }

        /// <summary>
        /// 向某一位客户端发送信息
        /// </summary>
        /// <param name="ip">客户端IP+端口地址</param>
        /// <param name="SendData">发送的数据包</param>
        public void SendToClient(ConnectedClient Client, string SendData)
        {
            try
            {
                ConnectedClient sks = ConnectedClients.Find(o=>o.Equals(Client));
                if (sks != null)
                {
                    if (sks.Client.Connected)
                    {
                        sks.SendBuffer = Encoding.GetEncoding("utf-8").GetBytes(SendData);
                        sks.Client.Client.Send(sks.SendBuffer, sks.SendBuffer.Length, 0);
                    }
                }
            }
            catch (Exception skex)
            {
                TcpMessageEventArgs e = new TcpMessageEventArgs(MessageType.Error, skex.ToString());
                if (MessageEvent != null)
                {
                    MessageEvent.Invoke(this, e);
                }
            }
        }
    }

    /// <summary>
    /// 表示服务器端连接的客户端
    /// </summary>
    public class ConnectedClient : IEquatable<ConnectedClient>
    {
        /// <summary>
        /// 接收缓冲区
        /// </summary>
        public byte[] RecBuffer = new byte[4096];
        /// <summary>
        /// 发送缓冲区
        /// </summary>
        public byte[] SendBuffer = new byte[4096];

        public TcpClient Client  { get; set; }

        public bool Equals(ConnectedClient other)
        {
           return ToString() == other.ToString()?true:false;
        }

        public override string ToString()
        {
            IPEndPoint iPEndPoint = Client.Client.RemoteEndPoint as IPEndPoint;
            return iPEndPoint.ToString();
        }


        public string IP
        {
            get { return (Client.Client.RemoteEndPoint as IPEndPoint).ToString(); }
          
        }

        public int Port
        {
            get { return (Client.Client.RemoteEndPoint as IPEndPoint).Port; }

        }
    }
    #endregion



    #region 客户端

    public class ClientReceiveDataEventArgs : EventArgs
    {
        public TCP_Client Client;
        public byte[] ReceiveData;
        public DateTime Time { get; set; }

        public ClientReceiveDataEventArgs(TCP_Client Client, byte[] ReceiveData)
        {
            this.ReceiveData = ReceiveData;
            this.Client = Client;
            Time = DateTime.Now;
        }
    }
    public class TCP_Client
    {
        public event EventHandler<ClientReceiveDataEventArgs> ReceiveDataEvent;
        public event EventHandler ClientOffLineEvent;
        public event EventHandler<TcpMessageEventArgs> MessageEvent;

        private byte[] _ReceiveBuffer = new byte[4096];

        public bool IsOpen
        {
            get { return client == null ? false : client.Connected; }
        }

        private TcpClient client;

        public bool Connect(string serverIp, int serverPort)
        {
            client = new TcpClient();
            client.Connect(new IPEndPoint(IPAddress.Parse(serverIp), serverPort));
            client.Client.BeginReceive(_ReceiveBuffer, 0, _ReceiveBuffer.Length, 0, new AsyncCallback(EndReader), client);
            return client.Connected;
        }
        private void EndReader(IAsyncResult ir)
        {
            TcpClient Client = ir.AsyncState as TcpClient;
            try
            {
                if (IsOpen == true)
                {
                    int ReceiveDataLengh = Client.GetStream().EndRead(ir);
                    if (ReceiveDataLengh != 0)
                    {
                        byte[] DataTemp = new byte[ReceiveDataLengh];
                        Array.Copy(_ReceiveBuffer, DataTemp, ReceiveDataLengh);
                       
                        if (ReceiveDataEvent != null)
                        {
                            ClientReceiveDataEventArgs ex = new ClientReceiveDataEventArgs(this, DataTemp);
                            ReceiveDataEvent.Invoke(this, ex);
                        }
                        Client.Client.BeginReceive(_ReceiveBuffer, 0, _ReceiveBuffer.Length, 0, new AsyncCallback(EndReader), Client);
                    }
                    else//客户端下线
                    {
                        if (ClientOffLineEvent != null)
                        {
                            ClientOffLineEvent.Invoke(this, null);
                        }
                        Stop();
                    }
                }
            }
            catch (Exception skex)
            {
                TcpMessageEventArgs e = new TcpMessageEventArgs(MessageType.Error, skex.Message);
                if (MessageEvent != null)
                {
                    MessageEvent.Invoke(this, e);
                }
            }
        }

        public void SendData(string SendData)
        {
            byte[] buffer = Encoding.GetEncoding("utf-8").GetBytes(SendData);
            this.SendData(buffer);
        }
        public void SendData(byte[] SendData)
        {
            byte[] buffer = SendData;
            client.Client.Send(buffer, buffer.Length, 0);
        }
     
        public void Stop()
        {
            if (!client.Connected)
            {
                return;
            }
            client.Client.Shutdown(SocketShutdown.Both);
            Thread.Sleep(10);
            client.Close();
        }
    }

    #endregion
}